let _toString = Object.prototype.toString;

function isRegExp(v) {
    return _toString.call(v) === '[object RegExp]'
}

/**
 * Remove an item from an array
 */
function remove(arr, item) {
    if (arr.length) {
        let index = arr.indexOf(item);
        if (index > -1) {
            return arr.splice(index, 1)
        }
    }
}


function isDef(v) {
    return v !== undefined && v !== null
}

function isAsyncPlaceholder(node) {
    return node.isComment && node.asyncFactory
}

function getFirstComponentChild(children) {
    if (Array.isArray(children)) {
        for (let i = 0; i < children.length; i++) {
            let c = children[i];
            if (isDef(c) && (isDef(c.componentOptions) || isAsyncPlaceholder(c))) {
                return c
            }
        }
    }
}

function matches(pattern, name) {
    if (Array.isArray(pattern)) {
        return pattern.indexOf(name) > -1
    } else if (typeof pattern === 'string') {
        return pattern.split(',').indexOf(name) > -1
    } else if (isRegExp(pattern)) {
        return pattern.test(name)
    }
    /* istanbul ignore next */
    return false
}

function pruneCache(keepAliveInstance, filter) {
    const {cache, keys, _vnode} = keepAliveInstance
    for (const key in cache) {
        const cachedNode = cache[key]
        if (cachedNode) {
            const name = cachedNode.key
            if (name && !filter(name)) {
                keepAliveInstance.$nextTick(()=>{
                    // console.log('delete1',name)
                    pruneCacheEntry(cache, key, keys)
                });
            }
        }
    }
}

function pruneCacheEntry(cache,key,keys,current) {
    const cached = cache[key]
    if (cached && (!current || cached.key !== current.key)) {
        // console.log('delete',key)
        cached.componentInstance.$destroy()
    }
    cache[key] = null
    remove(keys, key)
}

export default {
    name: 'keep-alive',
    abstract: true,

    created() {
        this.cache = {}
        this.keys = []
        this.preKey = null;
    },

    destroyed() {
        for (const key in this.cache) {
            pruneCacheEntry(this.cache, key, this.keys)
        }
    },
    computed: {
        cachePage(){
            return this.$store.state.tabView.pages.map(item => item.query['_']);
        },
        currentPage(){
            return this.$store.state.tabView.pages.filter(item => item.query['_'] == this.$store.state.tabView.currentPage)[0];
        }
    },

    watch: {
        cachePage(val) {
            pruneCache(this, name => matches(val, name))
        }
    },

    render() {
        const slot = this.$slots.default
        const vnode = getFirstComponentChild(slot);

        const key = this.$route.query['_'];
        let keepAlive = true;
        if(this.currentPage && typeof this.currentPage.keepAlive === "boolean"){
            keepAlive = this.currentPage.keepAlive;
        }
        // console.log(keepAlive)
        const componentOptions = vnode && vnode.componentOptions
        if (componentOptions) {

            const {cache, keys} = this
            // console.log(cache)

            vnode.key = key;
            if (cache[key] && (keepAlive || key === this.preKey)) {//key == this.preKey 处理vue多次渲染问题
                vnode.componentInstance = cache[key].componentInstance
                remove(keys, key)
                keys.push(key)
            } else {
                if(cache[key]){
                    // console.log('delete cache',key);
                    pruneCacheEntry(cache, key, keys);
                }

                this.$nextTick(() => {
                    cache[key] = vnode
                    keys.push(key)
                })

            }
            this.preKey = key;

            vnode.data.keepAlive = true
        }
        return vnode || (slot && slot[0])
    }
}
